package depta.dataregion.finder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.htmlparser.Node;
import org.htmlparser.util.NodeList;

import util.nodecloner.ChildFinder;

import depta.dataregion.DataRegion;
import depta.dataregion.MDR2;

public class DataRegionFinder {

	private static final int FIRST_LEVEL = 3;
	private Map<Node, List<DataRegion>> map;
	private MDR2 mdr2;
	private int K;
	private double threshold;

	public DataRegionFinder(MDR2 mdr2, int K, double threshold) {
		
		map = new HashMap<Node, List<DataRegion>>();
		
		this.mdr2 = mdr2;
		
		this.K = K;
		
		this.threshold = threshold;
		
	}
	
	public List<DataRegion> findDRs(Node n){
		
		if (MDR2.isAbove(n, FIRST_LEVEL)){
			
			List<DataRegion> drs = IdenDRs(0,n);
			
			map.put(n, drs);
			
			List<DataRegion> tempDRs = new ArrayList<DataRegion>();
			
			NodeList children = ChildFinder.getChildren(n);
			
			for (int i = 0; i < children.size(); i++) {
				
				findDRs(children.elementAt(i));
				
				tempDRs.addAll(UnCoveredDRs(n,children.elementAt(i),i,map));
				
			}
			
			drs.addAll(tempDRs);
			
			return drs;
		}
		
		List<DataRegion> r = new ArrayList<DataRegion>();
		
		map.put(n, r);
		
		return r;
	}

	private List<DataRegion> UnCoveredDRs(Node node, Node child, int index, Map<Node, List<DataRegion>> map) {
		
		List<DataRegion> DRs = map.get(node);
		
		for (DataRegion dataRegion : DRs) {
			
			if (dataRegion.inRange(index)){
				return new ArrayList<DataRegion>();
			}
			
		}
		
		List<DataRegion> ret = map.get(child);
		
		return ret;
		
	}

	private List<DataRegion> IdenDRs(int start, Node node) {
		
		int[] maxDR = {0,0,0};
		
		for (int i = 1; i <= K; i++) {
			
			for (int f = start; f < start+i; f++) {
				
				boolean flag = true;
				
				int[] curDR = new int[3];
				
				for (int j = f+i /*instead of f*/; j < ChildFinder.getChildren(node).size()-i+1 /*I added -i +1*/; j+=i) {
					
					if (Distance(node,i,ChildFinder.getChildren(node).elementAt(j-i/*instead of f*/),i,ChildFinder.getChildren(node).elementAt(j))<=threshold){
					
						if (flag == true){
							curDR[0] = i;
							curDR[1] = f; /*instead of j*/
							curDR[2] = 2*i;
							flag = false;
						}else{
							curDR[2] = curDR[2]+i;
						}
					} else if (flag == false){
						break;
					}

				}
				
				if ((maxDR[2]<curDR[2]) && (maxDR[1]==0 || curDR[1]<=maxDR[1]) && visualValid(curDR)){
					maxDR = curDR;
				}
			}
			
		}
		
		if (maxDR[2] != 0){
			if (maxDR[1]+maxDR[2]-1 != ChildFinder.getChildren(node).size()){
				
				List<DataRegion> ret = new ArrayList<DataRegion>();
				
				ret.add(new DataRegion(maxDR, node));
				
				ret.addAll(IdenDRs(maxDR[1]+maxDR[2], node));
				
				return ret;
						
			}else{
				
				List<DataRegion> ret = new ArrayList<DataRegion>();
				
				ret.add(new DataRegion(maxDR,node));
				
				return ret;
			}
		}
		
		return new ArrayList<DataRegion>();
		
	}

	private double Distance(Node node, int combination, Node initialNode1, int combination2, Node initialNode2) {
		return mdr2.getDistance(node,combination,initialNode1,combination2,initialNode2);
	}

	private boolean visualValid(int[] curDR) {
		// TODO Auto-generated method stub
		return true;
	}

	public List<DataRegion> getDataRegion(Node node){
		return map.get(node);
	}

	public int getK() {
		return K;
	}

	public double getThreshold() {
		return threshold;
	}

	public MDR2 getMdr() {
		return mdr2;
	}
		
}
